/* * jQuery Form Styler v1.7.8 * https://github.com/Dimox/jQueryFormStyler * * Copyright 2012-2017 Dimox (http://dimox.name/) * Released under the MIT license. * * Date: 2017.02.17 * */ ;(function(factory) { if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], factory); } else if (typeof exports === 'object') { // CommonJS module.exports = factory($ || require('jquery')); } else { factory(jQuery); } }(function($) { 'use strict'; var pluginName = 'styler', defaults = { idSuffix: '-styler', filePlaceholder: 'Файл не выбран', fileBrowse: 'Обзор...', fileNumber: 'Выбрано файлов: %s', selectPlaceholder: 'Выберите...', selectSearch: false, selectSearchLimit: 10, selectSearchNotFound: 'Совпадений не найдено', selectSearchPlaceholder: 'Поиск...', selectVisibleOptions: 0, singleSelectzIndex: '100', selectSmartPositioning: true, locale: 'ru', locales: { 'en': { filePlaceholder: 'No file selected', fileBrowse: 'Browse...', fileNumber: 'Selected files: %s', selectPlaceholder: 'Select...', selectSearchNotFound: 'No matches found', selectSearchPlaceholder: 'Search...' } }, onSelectOpened: function() {}, onSelectClosed: function() {}, onFormStyled: function() {} }; function Plugin(element, options) { this.element = element; this.options = $.extend({}, defaults, options); var locale = this.options.locale; if (this.options.locales[locale] !== undefined) { $.extend(this.options, this.options.locales[locale]); } this.init(); } Plugin.prototype = { // инициализация init: function() { var el = $(this.element); var opt = this.options; var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/i) && !navigator.userAgent.match(/(Windows\sPhone)/i)) ? true : false; var Android = (navigator.userAgent.match(/Android/i) && !navigator.userAgent.match(/(Windows\sPhone)/i)) ? true : false; function Attributes() { if (el.attr('id') !== undefined && el.attr('id') !== '') { this.id = el.attr('id') + opt.idSuffix; } this.title = el.attr('title'); this.classes = el.attr('class'); this.data = el.data(); } // checkbox if (el.is(':checkbox')) { var checkboxOutput = function() { var att = new Attributes(); var checkbox = $('
') .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; // прячем оригинальный чекбокс el.css({ position: 'absolute', zIndex: '-1', opacity: 0, margin: 0, padding: 0 }).after(checkbox).prependTo(checkbox); checkbox.attr('unselectable', 'on').css({ '-webkit-user-select': 'none', '-moz-user-select': 'none', '-ms-user-select': 'none', '-o-user-select': 'none', 'user-select': 'none', display: 'inline-block', position: 'relative', overflow: 'hidden' }); if (el.is(':checked')) checkbox.addClass('checked'); if (el.is(':disabled')) checkbox.addClass('disabled'); // клик на псевдочекбокс checkbox.click(function(e) { e.preventDefault(); if (!checkbox.is('.disabled')) { if (el.is(':checked')) { el.prop('checked', false); checkbox.removeClass('checked'); } else { el.prop('checked', true); checkbox.addClass('checked'); } el.focus().change(); } }); // клик на label el.closest('label').add('label[for="' + el.attr('id') + '"]').on('click.styler', function(e) { if (!$(e.target).is('a') && !$(e.target).closest(checkbox).length) { checkbox.triggerHandler('click'); e.preventDefault(); } }); // переключение по Space или Enter el.on('change.styler', function() { if (el.is(':checked')) checkbox.addClass('checked'); else checkbox.removeClass('checked'); }) // чтобы переключался чекбокс, который находится в теге label .on('keydown.styler', function(e) { if (e.which == 32) checkbox.click(); }) .on('focus.styler', function() { if (!checkbox.is('.disabled')) checkbox.addClass('focused'); }) .on('blur.styler', function() { checkbox.removeClass('focused'); }); }; // end checkboxOutput() checkboxOutput(); // обновление при динамическом изменении el.on('refresh', function() { el.closest('label').add('label[for="' + el.attr('id') + '"]').off('.styler'); el.off('.styler').parent().before(el).remove(); checkboxOutput(); }); // end checkbox // radio } else if (el.is(':radio')) { var radioOutput = function() { var att = new Attributes(); var radio = $('
') .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; // прячем оригинальную радиокнопку el.css({ position: 'absolute', zIndex: '-1', opacity: 0, margin: 0, padding: 0 }).after(radio).prependTo(radio); radio.attr('unselectable', 'on').css({ '-webkit-user-select': 'none', '-moz-user-select': 'none', '-ms-user-select': 'none', '-o-user-select': 'none', 'user-select': 'none', display: 'inline-block', position: 'relative' }); if (el.is(':checked')) radio.addClass('checked'); if (el.is(':disabled')) radio.addClass('disabled'); // определяем общего родителя у радиокнопок с одинаковым name // http://stackoverflow.com/a/27733847 $.fn.commonParents = function (){ var cachedThis = this; return cachedThis.first().parents().filter(function () { return $(this).find(cachedThis).length === cachedThis.length; }); }; $.fn.commonParent = function (){ return $(this).commonParents().first(); }; // клик на псевдорадиокнопке radio.click(function(e) { e.preventDefault(); if (!radio.is('.disabled')) { var inputName = $('input[name="' + el.attr('name') + '"]'); inputName.commonParent().find(inputName).prop('checked', false).parent().removeClass('checked'); el.prop('checked', true).parent().addClass('checked'); el.focus().change(); } }); // клик на label el.closest('label').add('label[for="' + el.attr('id') + '"]').on('click.styler', function(e) { if (!$(e.target).is('a') && !$(e.target).closest(radio).length) { radio.triggerHandler('click'); e.preventDefault(); } }); // переключение стрелками el.on('change.styler', function() { el.parent().addClass('checked'); }) .on('focus.styler', function() { if (!radio.is('.disabled')) radio.addClass('focused'); }) .on('blur.styler', function() { radio.removeClass('focused'); }); }; // end radioOutput() radioOutput(); // обновление при динамическом изменении el.on('refresh', function() { el.closest('label').add('label[for="' + el.attr('id') + '"]').off('.styler'); el.off('.styler').parent().before(el).remove(); radioOutput(); }); // end radio // file } else if (el.is(':file')) { // прячем оригинальное поле el.css({ position: 'absolute', top: 0, right: 0, margin: 0, padding: 0, opacity: 0, fontSize: '100px' }); var fileOutput = function() { var att = new Attributes(); var placeholder = el.data('placeholder'); if (placeholder === undefined) placeholder = opt.filePlaceholder; var browse = el.data('browse'); if (browse === undefined || browse === '') browse = opt.fileBrowse; var file = $('
' + '
' + placeholder + '
' + '
' + browse + '
' + '
') .css({ display: 'inline-block', position: 'relative', overflow: 'hidden' }) .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; el.after(file).appendTo(file); if (el.is(':disabled')) file.addClass('disabled'); el.on('change.styler', function() { var value = el.val(); var name = $('div.jq-file__name', file); if (el.is('[multiple]')) { value = ''; var files = el[0].files.length; if (files > 0) { var number = el.data('number'); if (number === undefined) number = opt.fileNumber; number = number.replace('%s', files); value = number; } } name.text(value.replace(/.+[\\\/]/, '')); if (value === '') { name.text(placeholder); file.removeClass('changed'); } else { file.addClass('changed'); } }) .on('focus.styler', function() { file.addClass('focused'); }) .on('blur.styler', function() { file.removeClass('focused'); }) .on('click.styler', function() { file.removeClass('focused'); }); }; // end fileOutput() fileOutput(); // обновление при динамическом изменении el.on('refresh', function() { el.off('.styler').parent().before(el).remove(); fileOutput(); }); // end file } else if (el.is('input[type="number"]')) { var numberOutput = function() { var att = new Attributes(); var number = $('
' + '
' + '
' + '
') .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; el.after(number).prependTo(number).wrap('
'); if (el.is(':disabled')) number.addClass('disabled'); var min, max, step, timeout = null, interval = null; if (el.attr('min') !== undefined) min = el.attr('min'); if (el.attr('max') !== undefined) max = el.attr('max'); if (el.attr('step') !== undefined && $.isNumeric(el.attr('step'))) step = Number(el.attr('step')); else step = Number(1); var changeValue = function(spin) { var value = el.val(), newValue; if (!$.isNumeric(value)) { value = 0; el.val('0'); } if (spin.is('.minus')) { newValue = Number(value) - step; } else if (spin.is('.plus')) { newValue = Number(value) + step; } // определяем количество десятичных знаков после запятой в step var decimals = (step.toString().split('.')[1] || []).length; if (decimals > 0) { var multiplier = '1'; while (multiplier.length <= decimals) multiplier = multiplier + '0'; // избегаем появления лишних знаков после запятой newValue = Math.round(newValue * multiplier) / multiplier; } if ($.isNumeric(min) && $.isNumeric(max)) { if (newValue >= min && newValue <= max) el.val(newValue); } else if ($.isNumeric(min) && !$.isNumeric(max)) { if (newValue >= min) el.val(newValue); } else if (!$.isNumeric(min) && $.isNumeric(max)) { if (newValue <= max) el.val(newValue); } else { el.val(newValue); } }; if (!number.is('.disabled')) { number.on('mousedown', 'div.jq-number__spin', function() { var spin = $(this); changeValue(spin); timeout = setTimeout(function(){ interval = setInterval(function(){ changeValue(spin); }, 40); }, 350); }).on('mouseup mouseout', 'div.jq-number__spin', function() { clearTimeout(timeout); clearInterval(interval); }).on('mouseup', 'div.jq-number__spin', function() { el.change(); }); el.on('focus.styler', function() { number.addClass('focused'); }) .on('blur.styler', function() { number.removeClass('focused'); }); } }; // end numberOutput() numberOutput(); // обновление при динамическом изменении el.on('refresh', function() { el.off('.styler').closest('.jq-number').before(el).remove(); numberOutput(); }); // end number // select } else if (el.is('select')) { var selectboxOutput = function() { // запрещаем прокрутку страницы при прокрутке селекта function preventScrolling(selector) { selector.off('mousewheel DOMMouseScroll').on('mousewheel DOMMouseScroll', function(e) { var scrollTo = null; if (e.type == 'mousewheel') { scrollTo = (e.originalEvent.wheelDelta * -1); } else if (e.type == 'DOMMouseScroll') { scrollTo = 40 * e.originalEvent.detail; } if (scrollTo) { e.stopPropagation(); e.preventDefault(); $(this).scrollTop(scrollTo + $(this).scrollTop()); } }); } var option = $('option', el); var list = ''; // формируем список селекта function makeList() { for (var i = 0; i < option.length; i++) { var op = option.eq(i); var li = '', liClass = '', liClasses = '', id = '', title = '', dataList = '', optionClass = '', optgroupClass = '', dataJqfsClass = ''; var disabled = 'disabled'; var selDis = 'selected sel disabled'; if (op.prop('selected')) liClass = 'selected sel'; if (op.is(':disabled')) liClass = disabled; if (op.is(':selected:disabled')) liClass = selDis; if (op.attr('id') !== undefined && op.attr('id') !== '') id = ' id="' + op.attr('id') + opt.idSuffix + '"'; if (op.attr('title') !== undefined && option.attr('title') !== '') title = ' title="' + op.attr('title') + '"'; if (op.attr('class') !== undefined) { optionClass = ' ' + op.attr('class'); dataJqfsClass = ' data-jqfs-class="' + op.attr('class') + '"'; } var data = op.data(); for (var k in data) { if (data[k] !== '') dataList += ' data-' + k + '="' + data[k] + '"'; } if ( (liClass + optionClass) !== '' ) liClasses = ' class="' + liClass + optionClass + '"'; li = ''+ op.html() +''; // если есть optgroup if (op.parent().is('optgroup')) { if (op.parent().attr('class') !== undefined) optgroupClass = ' ' + op.parent().attr('class'); li = ''+ op.html() +''; if (op.is(':first-child')) { li = '
  • ' + op.parent().attr('label') + '
  • ' + li; } } list += li; } } // end makeList() // одиночный селект function doSelect() { var att = new Attributes(); var searchHTML = ''; var selectPlaceholder = el.data('placeholder'); var selectSearch = el.data('search'); var selectSearchLimit = el.data('search-limit'); var selectSearchNotFound = el.data('search-not-found'); var selectSearchPlaceholder = el.data('search-placeholder'); var singleSelectzIndex = el.data('z-index'); var selectSmartPositioning = el.data('smart-positioning'); if (selectPlaceholder === undefined) selectPlaceholder = opt.selectPlaceholder; if (selectSearch === undefined || selectSearch === '') selectSearch = opt.selectSearch; if (selectSearchLimit === undefined || selectSearchLimit === '') selectSearchLimit = opt.selectSearchLimit; if (selectSearchNotFound === undefined || selectSearchNotFound === '') selectSearchNotFound = opt.selectSearchNotFound; if (selectSearchPlaceholder === undefined) selectSearchPlaceholder = opt.selectSearchPlaceholder; if (singleSelectzIndex === undefined || singleSelectzIndex === '') singleSelectzIndex = opt.singleSelectzIndex; if (selectSmartPositioning === undefined || selectSmartPositioning === '') selectSmartPositioning = opt.selectSmartPositioning; var selectbox = $('
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ') .css({ display: 'inline-block', position: 'relative', zIndex: singleSelectzIndex }) .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; el.css({margin: 0, padding: 0}).after(selectbox).prependTo(selectbox); var divSelect = $('div.jq-selectbox__select', selectbox); var divText = $('div.jq-selectbox__select-text', selectbox); var optionSelected = option.filter(':selected'); makeList(); if (selectSearch) searchHTML = '' + '
    ' + selectSearchNotFound + '
    '; var dropdown = $('
    ' + searchHTML + '
      ' + list + '
    ' + '
    '); selectbox.append(dropdown); var ul = $('ul', dropdown); var li = $('li', dropdown); var search = $('input', dropdown); var notFound = $('div.jq-selectbox__not-found', dropdown).hide(); if (li.length < selectSearchLimit) search.parent().hide(); // показываем опцию по умолчанию // если у 1-й опции нет текста, она выбрана по умолчанию и параметр selectPlaceholder не false, то показываем плейсхолдер if (option.first().text() === '' && option.first().is(':selected') && selectPlaceholder !== false) { divText.text(selectPlaceholder).addClass('placeholder'); } else { divText.text(optionSelected.text()); } // определяем самый широкий пункт селекта var liWidthInner = 0, liWidth = 0; li.css({'display': 'inline-block'}); li.each(function() { var l = $(this); if (l.innerWidth() > liWidthInner) { liWidthInner = l.innerWidth(); liWidth = l.width(); } }); li.css({'display': ''}); // подстраиваем ширину свернутого селекта в зависимости // от ширины плейсхолдера или самого широкого пункта if (divText.is('.placeholder') && (divText.width() > liWidthInner)) { divText.width(divText.width()); } else { var selClone = selectbox.clone().appendTo('body').width('auto'); var selCloneWidth = selClone.outerWidth(); selClone.remove(); if (selCloneWidth == selectbox.outerWidth()) { divText.width(liWidth); } } // подстраиваем ширину выпадающего списка в зависимости от самого широкого пункта if (liWidthInner > selectbox.width()) dropdown.width(liWidthInner); // прячем 1-ю пустую опцию, если она есть и если атрибут data-placeholder не пустой // если все же нужно, чтобы первая пустая опция отображалась, то указываем у селекта: data-placeholder="" if (option.first().text() === '' && el.data('placeholder') !== '') { li.first().hide(); } // прячем оригинальный селект el.css({ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', opacity: 0 }); var selectHeight = selectbox.outerHeight(true); var searchHeight = search.parent().outerHeight(true) || 0; var isMaxHeight = ul.css('max-height'); var liSelected = li.filter('.selected'); if (liSelected.length < 1) li.first().addClass('selected sel'); if (li.data('li-height') === undefined) { var liOuterHeight = li.outerHeight(); if (selectPlaceholder !== false) liOuterHeight = li.eq(1).outerHeight(); li.data('li-height', liOuterHeight); } var position = dropdown.css('top'); if (dropdown.css('left') == 'auto') dropdown.css({left: 0}); if (dropdown.css('top') == 'auto') { dropdown.css({top: selectHeight}); position = selectHeight; } dropdown.hide(); // если выбран не дефолтный пункт if (liSelected.length) { // добавляем класс, показывающий изменение селекта if (option.first().text() != optionSelected.text()) { selectbox.addClass('changed'); } // передаем селекту класс выбранного пункта selectbox.data('jqfs-class', liSelected.data('jqfs-class')); selectbox.addClass(liSelected.data('jqfs-class')); } // если селект неактивный if (el.is(':disabled')) { selectbox.addClass('disabled'); return false; } // при клике на псевдоселекте divSelect.click(function() { // колбек при закрытии селекта if ($('div.jq-selectbox').filter('.opened').length) { opt.onSelectClosed.call($('div.jq-selectbox').filter('.opened')); } el.focus(); // если iOS, то не показываем выпадающий список, // т.к. отображается нативный и неизвестно, как его спрятать if (iOS) return; // умное позиционирование var win = $(window); var liHeight = li.data('li-height'); var topOffset = selectbox.offset().top; var bottomOffset = win.height() - selectHeight - (topOffset - win.scrollTop()); var visible = el.data('visible-options'); if (visible === undefined || visible === '') visible = opt.selectVisibleOptions; var minHeight = liHeight * 5; var newHeight = liHeight * visible; if (visible > 0 && visible < 6) minHeight = newHeight; if (visible === 0) newHeight = 'auto'; var dropDown = function() { dropdown.height('auto').css({bottom: 'auto', top: position}); var maxHeightBottom = function() { ul.css('max-height', Math.floor((bottomOffset - 20 - searchHeight) / liHeight) * liHeight); }; maxHeightBottom(); ul.css('max-height', newHeight); if (isMaxHeight != 'none') { ul.css('max-height', isMaxHeight); } if (bottomOffset < (dropdown.outerHeight() + 20)) { maxHeightBottom(); } }; var dropUp = function() { dropdown.height('auto').css({top: 'auto', bottom: position}); var maxHeightTop = function() { ul.css('max-height', Math.floor((topOffset - win.scrollTop() - 20 - searchHeight) / liHeight) * liHeight); }; maxHeightTop(); ul.css('max-height', newHeight); if (isMaxHeight != 'none') { ul.css('max-height', isMaxHeight); } if ((topOffset - win.scrollTop() - 20) < (dropdown.outerHeight() + 20)) { maxHeightTop(); } }; if (selectSmartPositioning === true || selectSmartPositioning === 1) { // раскрытие вниз if (bottomOffset > (minHeight + searchHeight + 20)) { dropDown(); selectbox.removeClass('dropup').addClass('dropdown'); // раскрытие вверх } else { dropUp(); selectbox.removeClass('dropdown').addClass('dropup'); } } else if (selectSmartPositioning === false || selectSmartPositioning === 0) { // раскрытие вниз if (bottomOffset > (minHeight + searchHeight + 20)) { dropDown(); selectbox.removeClass('dropup').addClass('dropdown'); } } else { // если умное позиционирование отключено dropdown.height('auto').css({bottom: 'auto', top: position}); ul.css('max-height', newHeight); if (isMaxHeight != 'none') { ul.css('max-height', isMaxHeight); } } // если выпадающий список выходит за правый край окна браузера, // то меняем позиционирование с левого на правое if (selectbox.offset().left + dropdown.outerWidth() > win.width()) { dropdown.css({left: 'auto', right: 0}); } // конец умного позиционирования $('div.jqselect').css({zIndex: (singleSelectzIndex - 1)}).removeClass('opened'); selectbox.css({zIndex: singleSelectzIndex}); if (dropdown.is(':hidden')) { $('div.jq-selectbox__dropdown:visible').hide(); dropdown.show(); selectbox.addClass('opened focused'); // колбек при открытии селекта opt.onSelectOpened.call(selectbox); } else { dropdown.hide(); selectbox.removeClass('opened dropup dropdown'); // колбек при закрытии селекта if ($('div.jq-selectbox').filter('.opened').length) { opt.onSelectClosed.call(selectbox); } } // поисковое поле if (search.length) { search.val('').keyup(); notFound.hide(); search.keyup(function() { var query = $(this).val(); li.each(function() { if (!$(this).html().match(new RegExp('.*?' + query + '.*?', 'i'))) { $(this).hide(); } else { $(this).show(); } }); // прячем 1-ю пустую опцию if (option.first().text() === '' && el.data('placeholder') !== '') { li.first().hide(); } if (li.filter(':visible').length < 1) { notFound.show(); } else { notFound.hide(); } }); } // прокручиваем до выбранного пункта при открытии списка if (li.filter('.selected').length) { if (el.val() === '') { ul.scrollTop(0); } else { // если нечетное количество видимых пунктов, // то высоту пункта делим пополам для последующего расчета if ( (ul.innerHeight() / liHeight) % 2 !== 0 ) liHeight = liHeight / 2; ul.scrollTop(ul.scrollTop() + li.filter('.selected').position().top - ul.innerHeight() / 2 + liHeight); } } preventScrolling(ul); }); // end divSelect.click() // при наведении курсора на пункт списка li.hover(function() { $(this).siblings().removeClass('selected'); }); var selectedText = li.filter('.selected').text(); // при клике на пункт списка li.filter(':not(.disabled):not(.optgroup)').click(function() { el.focus(); var t = $(this); var liText = t.text(); if (!t.is('.selected')) { var index = t.index(); index -= t.prevAll('.optgroup').length; t.addClass('selected sel').siblings().removeClass('selected sel'); option.prop('selected', false).eq(index).prop('selected', true); selectedText = liText; divText.text(liText); // передаем селекту класс выбранного пункта if (selectbox.data('jqfs-class')) selectbox.removeClass(selectbox.data('jqfs-class')); selectbox.data('jqfs-class', t.data('jqfs-class')); selectbox.addClass(t.data('jqfs-class')); el.change(); } dropdown.hide(); selectbox.removeClass('opened dropup dropdown'); // колбек при закрытии селекта opt.onSelectClosed.call(selectbox); }); dropdown.mouseout(function() { $('li.sel', dropdown).addClass('selected'); }); // изменение селекта el.on('change.styler', function() { divText.text(option.filter(':selected').text()).removeClass('placeholder'); li.removeClass('selected sel').not('.optgroup').eq(el[0].selectedIndex).addClass('selected sel'); // добавляем класс, показывающий изменение селекта if (option.first().text() != li.filter('.selected').text()) { selectbox.addClass('changed'); } else { selectbox.removeClass('changed'); } }) .on('focus.styler', function() { selectbox.addClass('focused'); $('div.jqselect').not('.focused').removeClass('opened dropup dropdown').find('div.jq-selectbox__dropdown').hide(); }) .on('blur.styler', function() { selectbox.removeClass('focused'); }) // изменение селекта с клавиатуры .on('keydown.styler keyup.styler', function(e) { var liHeight = li.data('li-height'); if (el.val() === '') { divText.text(selectPlaceholder).addClass('placeholder'); } else { divText.text(option.filter(':selected').text()); } li.removeClass('selected sel').not('.optgroup').eq(el[0].selectedIndex).addClass('selected sel'); // вверх, влево, Page Up, Home if (e.which == 38 || e.which == 37 || e.which == 33 || e.which == 36) { if (el.val() === '') { ul.scrollTop(0); } else { ul.scrollTop(ul.scrollTop() + li.filter('.selected').position().top); } } // вниз, вправо, Page Down, End if (e.which == 40 || e.which == 39 || e.which == 34 || e.which == 35) { ul.scrollTop(ul.scrollTop() + li.filter('.selected').position().top - ul.innerHeight() + liHeight); } // закрываем выпадающий список при нажатии Enter if (e.which == 13) { e.preventDefault(); dropdown.hide(); selectbox.removeClass('opened dropup dropdown'); // колбек при закрытии селекта opt.onSelectClosed.call(selectbox); } }).on('keydown.styler', function(e) { // открываем выпадающий список при нажатии Space if (e.which == 32) { e.preventDefault(); divSelect.click(); } }); // прячем выпадающий список при клике за пределами селекта if (!onDocumentClick.registered) { $(document).on('click', onDocumentClick); onDocumentClick.registered = true; } } // end doSelect() // мультиселект function doMultipleSelect() { var att = new Attributes(); var selectbox = $('
    ') .css({ display: 'inline-block', position: 'relative' }) .attr({ id: att.id, title: att.title }) .addClass(att.classes) .data(att.data) ; el.css({margin: 0, padding: 0}).after(selectbox); makeList(); selectbox.append(''); var ul = $('ul', selectbox).css({ 'position': 'relative', 'overflow-x': 'hidden', '-webkit-overflow-scrolling': 'touch' }); var li = $('li', selectbox).attr('unselectable', 'on'); var size = el.attr('size'); var ulHeight = ul.outerHeight(); var liHeight = li.outerHeight(); if (size !== undefined && size > 0) { ul.css({'height': liHeight * size}); } else { ul.css({'height': liHeight * 4}); } if (ulHeight > selectbox.height()) { ul.css('overflowY', 'scroll'); preventScrolling(ul); // прокручиваем до выбранного пункта if (li.filter('.selected').length) { ul.scrollTop(ul.scrollTop() + li.filter('.selected').position().top); } } // прячем оригинальный селект el.prependTo(selectbox).css({ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', opacity: 0 }); // если селект неактивный if (el.is(':disabled')) { selectbox.addClass('disabled'); option.each(function() { if ($(this).is(':selected')) li.eq($(this).index()).addClass('selected'); }); // если селект активный } else { // при клике на пункт списка li.filter(':not(.disabled):not(.optgroup)').click(function(e) { el.focus(); var clkd = $(this); if(!e.ctrlKey && !e.metaKey) clkd.addClass('selected'); if(!e.shiftKey) clkd.addClass('first'); if(!e.ctrlKey && !e.metaKey && !e.shiftKey) clkd.siblings().removeClass('selected first'); // выделение пунктов при зажатом Ctrl if(e.ctrlKey || e.metaKey) { if (clkd.is('.selected')) clkd.removeClass('selected first'); else clkd.addClass('selected first'); clkd.siblings().removeClass('first'); } // выделение пунктов при зажатом Shift if(e.shiftKey) { var prev = false, next = false; clkd.siblings().removeClass('selected').siblings('.first').addClass('selected'); clkd.prevAll().each(function() { if ($(this).is('.first')) prev = true; }); clkd.nextAll().each(function() { if ($(this).is('.first')) next = true; }); if (prev) { clkd.prevAll().each(function() { if ($(this).is('.selected')) return false; else $(this).not('.disabled, .optgroup').addClass('selected'); }); } if (next) { clkd.nextAll().each(function() { if ($(this).is('.selected')) return false; else $(this).not('.disabled, .optgroup').addClass('selected'); }); } if (li.filter('.selected').length == 1) clkd.addClass('first'); } // отмечаем выбранные мышью option.prop('selected', false); li.filter('.selected').each(function() { var t = $(this); var index = t.index(); if (t.is('.option')) index -= t.prevAll('.optgroup').length; option.eq(index).prop('selected', true); }); el.change(); }); // отмечаем выбранные с клавиатуры option.each(function(i) { $(this).data('optionIndex', i); }); el.on('change.styler', function() { li.removeClass('selected'); var arrIndexes = []; option.filter(':selected').each(function() { arrIndexes.push($(this).data('optionIndex')); }); li.not('.optgroup').filter(function(i) { return $.inArray(i, arrIndexes) > -1; }).addClass('selected'); }) .on('focus.styler', function() { selectbox.addClass('focused'); }) .on('blur.styler', function() { selectbox.removeClass('focused'); }); // прокручиваем с клавиатуры if (ulHeight > selectbox.height()) { el.on('keydown.styler', function(e) { // вверх, влево, PageUp if (e.which == 38 || e.which == 37 || e.which == 33) { ul.scrollTop(ul.scrollTop() + li.filter('.selected').position().top - liHeight); } // вниз, вправо, PageDown if (e.which == 40 || e.which == 39 || e.which == 34) { ul.scrollTop(ul.scrollTop() + li.filter('.selected:last').position().top - ul.innerHeight() + liHeight * 2); } }); } } } // end doMultipleSelect() if (el.is('[multiple]')) { // если Android или iOS, то мультиселект не стилизуем // причина для Android - в стилизованном селекте нет возможности выбрать несколько пунктов // причина для iOS - в стилизованном селекте неправильно отображаются выбранные пункты if (Android || iOS) return; doMultipleSelect(); } else { doSelect(); } }; // end selectboxOutput() selectboxOutput(); // обновление при динамическом изменении el.on('refresh', function() { el.off('.styler').parent().before(el).remove(); selectboxOutput(); }); // end select // reset } else if (el.is(':reset')) { el.on('click', function() { setTimeout(function() { el.closest('form').find('input, select').trigger('refresh'); }, 1); }); } // end reset }, // init: function() // деструктор destroy: function() { var el = $(this.element); if (el.is(':checkbox') || el.is(':radio')) { el.removeData('_' + pluginName).off('.styler refresh').removeAttr('style').parent().before(el).remove(); el.closest('label').add('label[for="' + el.attr('id') + '"]').off('.styler'); } else if (el.is('input[type="number"]')) { el.removeData('_' + pluginName).off('.styler refresh').closest('.jq-number').before(el).remove(); } else if (el.is(':file') || el.is('select')) { el.removeData('_' + pluginName).off('.styler refresh').removeAttr('style').parent().before(el).remove(); } } // destroy: function() }; // Plugin.prototype $.fn[pluginName] = function(options) { var args = arguments; if (options === undefined || typeof options === 'object') { this.each(function() { if (!$.data(this, '_' + pluginName)) { $.data(this, '_' + pluginName, new Plugin(this, options)); } }) // колбек после выполнения плагина .promise() .done(function() { var opt = $(this[0]).data('_' + pluginName); if (opt) opt.options.onFormStyled.call(); }); return this; } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { var returns; this.each(function() { var instance = $.data(this, '_' + pluginName); if (instance instanceof Plugin && typeof instance[options] === 'function') { returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1)); } }); return returns !== undefined ? returns : this; } }; // прячем выпадающий список при клике за пределами селекта function onDocumentClick(e) { // e.target.nodeName != 'OPTION' - добавлено для обхода бага в Opera на движке Presto // (при изменении селекта с клавиатуры срабатывает событие onclick) if (!$(e.target).parents().hasClass('jq-selectbox') && e.target.nodeName != 'OPTION') { if ($('div.jq-selectbox.opened').length) { var selectbox = $('div.jq-selectbox.opened'), search = $('div.jq-selectbox__search input', selectbox), dropdown = $('div.jq-selectbox__dropdown', selectbox), opt = selectbox.find('select').data('_' + pluginName).options; // колбек при закрытии селекта opt.onSelectClosed.call(selectbox); if (search.length) search.val('').keyup(); dropdown.hide().find('li.sel').addClass('selected'); selectbox.removeClass('focused opened dropup dropdown'); } } } onDocumentClick.registered = false; }));